home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-07-28 | 17.0 KB | 775 lines | [TEXT/MPS ] |
- /*
- File: Application.cp
-
- Contains: xxx put contents here xxx
-
- Written by: Tim Harnett
-
- Copyright: © 1994 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <28> 2/27/95 TMH adapt to use ETO16 universal headers
- <27> 2/15/95 TMH moved gEnableIOTrace here, use of GetSlot(slotCID)
- <26> 2/14/95 CL CAttribute & CRecord I/F changes
- <25> 2/14/95 TMH change gEnabledEWorldSlot to gHFSSlotEnabled
- <24> 2/14/95 TMH added use of TSlotThread::IsLetterInTheEventQueue
- <23> 2/10/95 TMH change so modify events are posted while the slot is busy
- <22> 2/9/95 TMH added LimitErrorReport flag
- <21> 2/8/95 TMH fixed so we finnish sending on quit and shutdown events
- <19> 2/6/95 TMH adapt to CEventQueue modifications
- <18> 12/20/94 TMH implement location eppc, removed some debugger breaks
- <17> 12/16/94 TMH removed ReSignal() in ::Run()
- <16> 12/15/94 TMH added gAssertsEnabled
- <15> 12/13/94 TMH avoid duplicate postings of some events
- <14> 12/12/94 TMH use of thread events
- <13> 11/2/94 TMH added initalize gEnableIOTrace from resource
- <12> 10/20/94 TMH validate system configuration
- <11> 10/20/94 TMH handle 'cnct' apple event
- <10> 10/18/94 TMH when a slot is created we put a entry into the setup record for
- the directory
- <9> 10/14/94 TMH fixed AppleEvent dispatching to work correctly
- <8> 10/11/94 TMH CommThread integration
- <7> 10/7/94 TMH fix so no crash if fail during IApplication
- <6> 10/6/94 JHB Added support for Gestalt checking
- <5> 10/6/94 TMH better error handling during initialization
- <4> 10/4/94 TMH added debug flag BreakEveryScheduleEPPC
- <3> 10/3/94 TMH added debug flag resource read
- <2> 9/30/94 TMH move incoming stuff to SlotThread
- <2> 9/30/94 TMH moved incoming stuff to slot thread
- <1> 9/21/94 TMH Use new Debug.cp ASSERT stuff,oops don't know how it got
- orphaned.
- <2> 9/21/94 TMH move thread stuff to TThread.cp,.h and SlotThread.cp,.h
- <1> 9/20/94 TMH Abandon RoadsideRest embrace Mercury
- <4> 9/20/94 TMH some experimental but working threaded stuff
- <3> 9/9/94 TMH catch more failures, TIncoming/TOutgoing adaptations
- <2> 6/17/94 TMH experimental thread stuff
- 3/29/94 TMH xxx put comment here xxx
-
- To Do:
- */
-
- #ifndef __RESOURCES__
- #include "Resources.h"
- #endif
-
- #ifndef __APPLEEVENTS__
- #include "AppleEvents.h"
- #endif
-
- #ifndef __AEREGISTRY__
- #include "AERegistry.h"
- #endif
-
-
- #ifndef __SOUND__
- #include <sound.h>
- #endif
-
-
- #ifndef __OCEERRORS__
- #include "OCEErrors.h"
- #endif
-
- #ifndef __Debug__
- #include "Debug.h"
- #endif
-
- #ifndef __PMSAMResources__
- #include "PMSAMResources.h"
- #endif
-
- #ifndef __PMSAMResourceIDs__
- #include "PMSAMResourceIDs.h"
- #endif
-
- #ifndef __CRecordID__
- #include "CRecordID.h"
- #endif
-
- #ifndef __CAttribute__
- #include "CAttribute.h"
- #endif
-
- #ifndef __Application__
- #include "Application.h"
- #endif
-
- #ifndef __Thread__
- #include "TThread.h"
- #endif
-
- #ifndef __SlotThread__
- #include "SlotThread.h"
- #endif
-
- #ifndef __MSAMSlot__
- #include "MSAMSlot.h"
- #endif
-
- #ifndef __ExternalSlot__
- #include "ExternalSlot.h"
- #endif
-
- #ifndef __HalfGateway__
- #include "HalfGateway.h"
- #endif
-
- #ifndef __ALetter__
- #include "ALetter.h"
- #endif
-
- #ifndef __XLetter__
- #include "XLetter.h"
- #endif
-
- #ifndef __Globals__
- #include "Globals.h"
- #endif
-
-
- #ifndef __UFAILURE__
- #include "UFailure.h"
- #endif
-
- #ifndef __LogErrors__
- #include "LogErrors.h"
- #endif
-
- #ifndef __CheckGestalt__
- #include "CheckGestalt.h"
- #endif
-
-
- //--------------------------------------
- // m a i n
- //--------------------------------------
-
- //•••••••••
-
- TApplicationThread* gApplicationThread = 0;
-
- CSystemConfiguration* gSystemConfiguration = 0;
-
- // debug flags
- Boolean gBreakEveryScheduleEPPC = false;
- Boolean gRunIfKeychainLocked = true;
- Boolean gDiagnosticsEnabled = false;
- Boolean gHFSSlotEnabled = false;
- Boolean gEnableIOTrace = true;
-
- //-------------------------------------------------------------------------------------------------
- void PlaySound( short resID ); // the compiler insists
- void PlaySound( short resID )
- {
- Handle aHandle = GetResource('snd ', resID);
- if ( aHandle != NULL ) {
- HLock(aHandle);
- OSErr result = SndPlay( NULL, (SndListHandle)aHandle, false );
- HUnlock(aHandle);
- ReleaseResource(aHandle);
- } else {
- SysBeep(20);
- }
- }
-
-
- //•••••••••••••••••
-
- //----------------------------------------------------------------
- void ValidateSystem(); // the compiler insists
- void ValidateSystem()
- {
- ASSERT(gSystemConfiguration);
-
- // We don't check for 7.1 or for PowerTalk. We assume
- // because we ARE running that our system has these.
-
- if( !gSystemConfiguration->HasCommToolbox() )
- FailOSErr(errCommToolBoxNotInstalled);
-
- if( !gSystemConfiguration->HasThreadManager() )
- FailOSErr(errThreadMgrNotInstalled);
-
-
- if( !gSystemConfiguration->HasAppleEvents() )
- FailOSErr(errNeedAppleEventSupport);
-
-
- }
-
-
-
-
- //-------------------------------------------------------------------------------------
- void main(void)
- {
-
- // Initialize the Toolbox
-
-
- Ptr aMaxStackPtr;
-
- aMaxStackPtr = GetApplLimit();
- aMaxStackPtr -= 0x4000;
- SetApplLimit(aMaxStackPtr);
- MaxApplZone();
- MoreMasters();
- MoreMasters();
- // InitGraf(&qd.thePort);
-
- ASSERT(0);
-
-
- // Read in the debug flags
-
-
- extern Boolean gHFSSlotEnabled;
- extern Boolean gBreakEveryScheduleEPPC;
- extern Boolean gRunIfKeychainLocked;
- extern Boolean gEnableIOTrace;
- extern Boolean gAssertsEnabled;
- extern Boolean gRecieveAfterSendNow;
- extern Boolean gLimitErrorReports;
- extern Boolean gDiagnosticsEnabled;
- Handle rsrc = ::Get1Resource('Dflg',0);
- if( rsrc != 0 ) {
- gHFSSlotEnabled = ( ((**(char**)rsrc) & bHFSSlotEnable) != 0);
- gBreakEveryScheduleEPPC = ( ((**(char**)rsrc) & bBreakOnScheduleEPPC) != 0);
- gRunIfKeychainLocked = ( ((**(char**)rsrc) & bRunIfKeychainLocked) != 0);
- gEnableIOTrace = ( ((**(char**)rsrc) & bEnableCommCaptureFile) != 0);
- gAssertsEnabled = ( ((**(char**)rsrc) & bEnableAsserts) != 0);
- gRecieveAfterSendNow = ( ((**(char**)rsrc) & bRecieveAfterSendNow) != 0);
- gLimitErrorReports = ( ((**(char**)rsrc) & bLimitErrorReports) != 0);
- gDiagnosticsEnabled = ( ((**(char**)rsrc) & bDiagnosticsEnabled) != 0);
- }
-
-
- gApplication = new TApplication;
-
- FailInfo fi;
- Try(fi) {
-
- gSystemConfiguration = new CSystemConfiguration;
- ValidateSystem();
-
- gApplication->IApplication();
- gApplication->Run();
- fi.Success();
- } else {
-
- // The place is comin' apart! We are outa here!
- LogError(fi.error);
-
- }
-
-
-
-
- }
-
- //--------------------------------------
- // T A p p l i c a t i o n
- //--------------------------------------
-
- //-------------------------------------------------------------------------------------
- TApplication::TApplication()
- {
- fAOCEHalfGateway = 0;
-
- fSetupRecordCID.source = fSetupRecordCID. seq = 0;
- fOCELocation = 0;
-
- fWNESleepTime = kSleepTime;
- }
-
-
- //-------------------------------------------------------------------------------------
- void TApplication::IApplication()
- {
-
- // All the errors here are considered fatal. Expect the application to
- // not start.
-
- this->InitializeAppleEvents();
-
- gApplicationThread = new TApplicationThread;
- gApplicationThread->IApplicationThread();
-
-
- fAOCEHalfGateway = new TAOCEHalfGateway;
-
- this->InitAuth();
-
- // Get AOCE keychain catalog
-
- DirParamBlock dirPB;
- memset(&dirPB,0,sizeof(DirParamBlock));
- DirGetOCESetupRefNum(&dirPB,false); // Note that this cannot fail. Ever.
-
- gKeyChainDSRefnum = dirPB.dirGetOCESetupRefNumPB.dsRefNum;
-
-
- // I'm At ... Location
-
-
- fSetupRecordCID = dirPB.dirGetOCESetupRefNumPB.oceSetupRecordCID;
- CRecordID setupRID(gKeyChainDSRefnum ,fSetupRecordCID);
- CAttribute locationAttr(kLocationAttrTypeNum);
- OSErr osErr = locationAttr.Read1Value(setupRID,&fOCELocation,sizeof(OCESetupLocation), gIdentity);
- ASSERTNOERR(osErr);
- FailOSErr(osErr);
-
-
- // MSAM Record
-
-
- MSAMParam mailPB;
- memset(&mailPB,0,sizeof(MSAMParam));
- osErr = PMSAMGetMSAMRecord(&mailPB);
- ASSERTNOERR(osErr);
- if (osErr!=noErr)
- FailOSErr(errMSAMSetupInfoCorrupt);
-
-
- // Read the configuration info for the slots.
-
-
- fAOCEHalfGateway->SetupSlots(mailPB.pmsamGetMSAMRecord.msamCID);
-
-
-
- }
-
-
-
-
- //-------------------------------------------------------------------------------------
- OSErr TApplication::InitAuth(void)
- {
- AuthParamBlock authBlock;
-
- OSErr osErr = AuthGetLocalIdentity(&authBlock,false);
- ASSERTNOERR(osErr);
- if( osErr != 0 && !gRunIfKeychainLocked) {
- PlaySound(2000);
- FailOSErr(errAlreadyLogged); // Pointless to log this. The mail box is not open!
- }
-
- gIdentity = authBlock.getLocalIdentityPB.theLocalIdentity;
-
-
- return osErr;
- }
-
-
-
-
-
- //-------------------------------------------------------------------------------------
- void TApplication::Run()
- {
- EventRecord theEvent;
- Boolean gotEvt;
- long astackspace;
-
- FailInfo fi;
- while (!gDone) {
-
- Try(fi) {
-
-
- gotEvt = false;
- gotEvt = WaitNextEvent(highLevelEventMask,&theEvent,fWNESleepTime,nil);
-
- gCurrentThread->Yield();
-
- if (gotEvt) {
-
- this->HandleEvent(&theEvent);
-
- } else {
-
- // Time to see if we got any letters put in our inBin
- astackspace= StackSpace();
- ASSERTPRINT(astackspace>1024, ("Stack is low!\n"));
-
- }
-
-
- fi.Success();
-
-
- } else {
-
- gDone = true;
- LogError(fi.error);
-
- }
-
-
- }
-
-
- }
-
-
-
- //-------------------------------------------------------------------------------------
- void TApplication::HandleEvent(EventRecord *theEvent)
- {
-
- switch (theEvent->what) {
- case kHighLevelEvent:
- this->HandleHighLevelEvent(theEvent);
- break;
- }
-
- }
-
-
-
- //-------------------------------------------------------------------------------------
- void TApplication::HandleHighLevelEvent(EventRecord *theEvent)
- {
-
- if( theEvent->message == kMailAppleMailCreator ) {
-
-
- // We accept only MailEPPCMsg
-
-
- TargetID sender;
- unsigned long refCon;
- unsigned long msgLen = 0;
- MailEPPCMsg mailEPPC;
- MailEPPCMsg* msgPtr = 0;
- OSErr err = AcceptHighLevelEvent(&sender,&refCon,(Ptr)&mailEPPC,&msgLen);
- if (err == bufferIsSmall ) {
- if( msgLen == sizeof(MailEPPCMsg) )
- msgPtr = &mailEPPC;
- err = AcceptHighLevelEvent(&sender,&refCon,(Ptr)msgPtr,&msgLen);
- }
- ASSERTNOERR(err);
-
- if( err == 0 ) {
- OSType messageID = * (unsigned long *) &theEvent->where;
- short slotID = (short)theEvent->modifiers;
-
- if( msgPtr != 0 && mailEPPC.version != kMailEPPCMsgVersion)
- FailOSErr(kOCEVersionErr);
-
-
- this->DoGatewayEvent(slotID, messageID, msgPtr);
- }
-
-
- } else {
-
- OSErr theErr = AEProcessAppleEvent(theEvent);
- //if (theErr != errAEEventNotHandled) // If the event is one we don't handle, do nothing
- // FailOSErr(theErr);
-
- }
-
-
- }
-
-
-
- //-------------------------------------------------------------------------------------
- void TApplication::DoGatewayEvent(short slotID, long messageID,MailEPPCMsg* theEppc)
- {
-
- TSlotThread* slotThread = 0;
- TMSAMSlot* msamSlot;
-
-
- long threadEventID = 0;
- long threadEventData0 = 0;
- Boolean allowDuplicateThreadEvent = kAllowDuplicateEvent;
-
-
- SMCA* smca = 0;
- if(theEppc != 0 )
- smca = theEppc->u.theSMCA;
-
-
-
- switch (messageID) {
-
- case kMailEPPCCreateSlot:
-
- ASSERT(smca);
-
-
- // Create the slot id attribute.
-
- {
- CRecordID slotRecord(gKeyChainDSRefnum,smca->u.slotCID);
- CAttribute slotIDAttr(kSlotIDAttrTypeNum);
- short newSlotID = 1; // hard code we handle only one for now.
- OSErr osErr = slotIDAttr.Write1Value(slotRecord,&newSlotID,sizeof(short), gIdentity);
- ASSERTNOERR(osErr);
-
- msamSlot = fAOCEHalfGateway->GetSlot(smca->u.slotCID);
- ASSERT(msamSlot);
- msamSlot->SetSlotID(newSlotID);
-
- gDone = true; // restart the PMSAM it works better that way!
-
- smca->result = noErr;
- }
- break;
-
-
- case kMailEPPCContinue:
- case kMailEPPCSchedule:
-
- // ... Only if we are not busy.
-
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
- if( (msamSlot != 0) && msamSlot->IsEnabled() && !msamSlot->Busy() )
- threadEventID = messageID;
-
- break;
-
-
-
- case kMailEPPCModifySlot:
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
- if( msamSlot != 0) {
- allowDuplicateThreadEvent = kDontAllowDuplicateEvent;
- threadEventID = messageID;
- }
-
- smca->result = noErr;
- break;
-
- case kMailEPPCMsgPending:
-
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
- if( (msamSlot != 0) && msamSlot->IsEnabled() && !msamSlot->Busy() ) {
- allowDuplicateThreadEvent = kDontAllowDuplicateEvent;
- threadEventID = messageID;
- }
-
- smca->result = noErr;
-
- break;
-
-
- case kMailEPPCSendImmediate:
-
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
-
- if( msamSlot != 0 && msamSlot->IsEnabled() ) {
-
- slotThread = msamSlot->GetSlotThread();
- ASSERT(slotThread);
-
- long letterSeqNo = smca->userBytes;
- if( !slotThread->IsLetterInTheEventQueue(letterSeqNo) ) { // Not the same letter twice.
- threadEventID = kMailEPPCSendImmediate;
- threadEventData0 = letterSeqNo;
- }
-
-
- }
-
- smca->result = noErr;
-
- break;
-
- case kMailEPPCLocationChanged:
-
- fOCELocation = theEppc->u.locationInfo.location;
-
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
- ASSERT(msamSlot!=0);
- if( msamSlot != 0 ) {
- msamSlot->SetLocationFlags(theEppc->u.locationInfo.active);
- allowDuplicateThreadEvent = kDontAllowDuplicateEvent;
- threadEventID = kMailEPPCModifySlot;
- }
- break;
-
-
- case kMailEPPCDeleteSlot:
- ASSERT(smca);
- DebugStr("\p Received kMailEPPCDeleteSlot;g");
- smca->result = noErr;
- break;
-
- case kMailEPPCShutDown:
-
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
- slotThread = msamSlot->GetSlotThread();
- ASSERT(slotThread);
-
- slotThread->FlushEvents('all '); // remove pending events
- slotThread->SetUserInterrupt('disc');
-
- while( msamSlot != 0 && msamSlot->Busy() ) // if busy finish sending
- gCurrentThread->Yield();
-
- gDone = true;
-
- break;
-
- case kMailEPPCWakeup:
- DebugStr("\p Received kMailEPPCWakeup;g");
- break;
-
-
- // Don't care about these.
-
-
- case kMailEPPCInQUpdate:
- case kMailEPPCMsgOpened:
- case kMailEPPCMailboxOpened:
- case kMailEPPCMailboxClosed:
- break;
-
- case kMailEPPCDeleteOutQMsg:
-
-
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
- if( msamSlot != 0 ) {
-
- slotThread = msamSlot->GetSlotThread();
- ASSERT(slotThread);
-
- slotThread->IsLetterInTheEventQueue(smca->userBytes,true);
- }
-
- //••• still need to check if the message is the one currently being sent.
- break;
-
-
- case 'disc': // disconnect -- only via AppleScript
-
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
- if( msamSlot != 0 && msamSlot->Busy() ) { // don't bother if we are not already disconnected
-
- slotThread = msamSlot->GetSlotThread();
- ASSERT(slotThread);
-
- slotThread->FlushEvents(kMailEPPCSendImmediate); // remove pending "send now's"
-
- slotThread->SetUserInterrupt('disc');
-
- }
-
- break;
-
- default:
- ASSERTPRINT(false,("Unrecognized MSAM EPPC message\n"));
- break;
- };
-
-
-
- if( threadEventID != 0 ) {
-
- msamSlot = fAOCEHalfGateway->GetSlot(slotID);
- ASSERT(msamSlot!=0);
- if( msamSlot != 0 ) {
-
- slotThread = msamSlot->GetSlotThread();
- ASSERT(slotThread);
- if( slotThread != 0)
- slotThread->PostEvent(threadEventID,threadEventData0,allowDuplicateThreadEvent);
-
- }
-
- }
-
-
-
- }
-
-
- //--------------------------------------------------------------------------------------------------------
- void TApplication::InitializeAppleEvents()
- {
-
- // Look for all AppleEvent dispatch tables…
- short numberOfTables = Count1Resources('aedt');// Count the number of 'aedt' resources
- FailResError();
-
- Handle tableHandle = NULL;
-
- FailInfo fi;
- Try(fi)
- {
- for (short tableIndex = 1; tableIndex <= numberOfTables; ++tableIndex)
- {
- tableHandle = Get1IndResource('aedt', tableIndex);
- FailResError();
-
- HLock(tableHandle);
-
- Size tableSize = GetHandleSize(tableHandle);
- FailMemError();
-
- short tableElements = (short)(tableSize / sizeof(AEDTResource));
-
- AEDTResource* tablePtr = (AEDTResource*) *tableHandle;
-
- for (short eventIndex = 1; eventIndex <= tableElements; ++eventIndex)
- {
- // Install a single event handler for all events
- OSErr osErr = AEInstallEventHandler(tablePtr->eventClass, tablePtr->eventID, (AEEventHandlerProcPtr) TApplication::AppleEventsDispatch, tablePtr->eventRefCon, false);
- FailOSErr(osErr);
-
- ++tablePtr;
- }
-
- HUnlock(tableHandle);
- ReleaseResource(tableHandle);
- }
- fi.Success();
- }
- else // Recover
- {
- if (tableHandle)
- {
- HUnlock(tableHandle);
- ReleaseResource(tableHandle);
- }
- fi.ReSignal();
- }
- }
-
- //----------------------------------------------------------------------------------------------------------------
- pascal OSErr TApplication::AppleEventsDispatch(AppleEvent* /*message*/,AppleEvent* /*reply*/, long refCon)
- {
- OSErr osErr = 0;
-
- switch (refCon) {
-
- case kAEOpenApplication:
- case kAEOpenDocuments:
- case kAEPrintDocuments:
- break;
- case kAEQuitApplication:
- gApplication->DoGatewayEvent(1,kMailEPPCShutDown,0);
- gDone = true;
- break;
- case 'cnct': // connect
- gApplication->DoGatewayEvent(1,kMailEPPCSchedule,0);
- break;
- case 'disc': // disconnect
- gApplication->DoGatewayEvent(1,'disc',0);
- break;
-
- default:
- ASSERTPRINT(false,("Unrecognized AppleEvent\n"));
- break;
-
- }
-
- return osErr;
- }
-